/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package linkedlist;

/**
 *
 * @author Islam Hamdi
 */
public class MyLinkedListD<T> {
private NodeD<T> header;// Pointing to the beginning
	private NodeD<T> trailer;// pointing to the end
	private long size;// size of the list

	/** Default constructor that creates an empty list */
	public MyLinkedListD() {
		size = 0;
		trailer = new NodeD<T>();
		header = new NodeD<T>();
		trailer.setPrev(header);
		header.setNext(trailer);
	}

	/** Construct a linkedList with a specified size */
	public MyLinkedListD(int listSize) {
		size = listSize;
		header = new NodeD<T>();
		trailer = new NodeD<T>();
		trailer.setPrev(header);
		header.setNext(trailer);
	}

	/**
	 * inserts the specified element at the specified position in the list
	 */
	public void add(int index, T element) {
		if (index <= 0 || index > size + 1) {
			throw new IllegalArgumentException("Index Not found !");
		} else {
			NodeD<T> temp = header.getNext();
			NodeD<T> newNode = new NodeD<T>(element);
			if (index == 1) {// if at the beginning of the list
				newNode.setNext(temp);
				newNode.setPrev(header);
				temp.setPrev(newNode);
				header.setNext(newNode);
				temp = null;
			} else {
				NodeD<T> temp1 = temp;
				// tracking NodeD till the specified index
				for (int counter = 1; counter < index; counter++) {
					temp1 = temp;
					temp = temp.getNext();
				}
				// inserting new node
				newNode.setNext(temp);
				newNode.setPrev(temp1);
				temp1.setNext(newNode);
				temp.setPrev(newNode);
			}
			size++;
		}
	}

	/** Inserts the specified element at the end of the list. */
	public void add(T element) {
		add((int) size + 1, element);
		// NodeD<T> end = new NodeD<T>(element);
		// if (size == 0) {
		// header.setNext(end);
		// end.setPrev(header);
		// end.setNext(trailer);
		// trailer.setPrev(end);
		// } else {
		// NodeD<T> last = getNode((int) size);
		// last.setNext(end);
		// end.setPrev(last);
		// trailer.setPrev(end);
		// end.setNext(trailer);
		// }
		// size++;
		// NodeD end = new NodeD(element);
		// if (size == 0) {
		// header.setNext(end);
		// } else {
		// NodeD n = header.getNext();
		// NodeD temp = n;
		// while (n != null) {
		// temp = n;
		// n = n.getNext();
		// }
		// temp.setNext(end);
		// }
		// size++;
	}

	/** returns a pointer to the node at the specified index */
	public NodeD<T> getNode(int index) {
		if (index <= 0 || index > size) {
			throw new IllegalArgumentException("Index Not found !");
		} else {
			int counter = 1;
			NodeD<T> temp = header.getNext();
			while (counter != index) {
				temp = temp.getNext();
				counter++;
			}
			return temp;
		}
	}

	/** returns the element at the specified position in the list */
	public T get(int index) {
		return getNode(index).getElement();
		// if (index <= 0 || index > size) {
		// throw new IllegalArgumentException("Index Not found !");
		// } else {
		// int counter = 1;
		// NodeD<T> temp = header.getNext();
		// while (counter != index) {
		// temp = temp.getNext();
		// counter++;
		// }
		// return temp.getElement();
		// }
	}

	/**
	 * replaces the element at the specified postition in this list with the
	 * specified element
	 */
	public void set(int index, T element) {
		NodeD<T> temp = getNode(index);
		temp.setElement(element);
	}

	/** removes all of the elements from this list */
	public void clear() {
            size=0;
		header.setNext(trailer);
		trailer.setPrev(header);
	}

	/** returns true if this list contains no elements */
	public boolean isEmpty() {
		if (size == 0) {
			return true;
		} else {
			return false;
		}
	}

	/** removes the element at the specified postition in this list */
	public void remove(int index) {
		if (index <= 0 || index > size) {
			throw new IllegalArgumentException("Index not found!");
		} else {
			if (index == 1) {
				header.setNext(trailer);
				trailer.setPrev(header);
			} else {
				NodeD<T> prev = getNode(index - 1);
				NodeD<T> temp = prev.getNext();
				prev.setNext(temp.getNext());
				temp.getNext().setPrev(prev);
				temp.setNext(null);
				temp.setPrev(null);
				// NodeD temp = header.getNext();
				// NodeD prev = temp;
				// int counter = 1;
				// while (counter != index) {
				// prev = temp;
				// temp = temp.getNext();
				// counter++;
				// }
				// prev.setNext(temp.getNext());
			}
			size--;
		}
	}

	/** returns the number of elements in this list */
	public int size() {
		return (int) size;
	}

	/** returns pointer to the header of the list */
	public NodeD<T> getHeader() {
		return header;
	}

	/** returns pointer to the trailer of the list */
	public NodeD<T> getTrailer() {
		return trailer;
	}

	/**
	 * returns a view of the portion of this list between the specified
	 * fromIndex and toIndex, inclusively
	 */
	public MyLinkedListD<T> sublist(int fromIndex, int toIndex) {
		if (fromIndex <= 0 || toIndex > size) {
			throw new IllegalArgumentException("Index Out of bounds !");
		} else {
			MyLinkedListD<T> portion = new MyLinkedListD<T>(toIndex - fromIndex
					+ 1);
			NodeD<T> temp = getNode(fromIndex);
			NodeD<T> first = new NodeD<T>(temp.getElement());
			portion.getHeader().setNext(first);
			first.setPrev(portion.getHeader());
			NodeD<T> pointer = first;
			for (int i = fromIndex + 1; i <= toIndex; i++) {
				NodeD<T> n = new NodeD<T>(get(i));
				pointer.setNext(n);
				n.setPrev(pointer);
				pointer = pointer.getNext();
				// temp = temp.getNext();
			}
			pointer.setNext(portion.getTrailer());
			portion.getTrailer().setPrev(pointer);
			return portion;
		}
	}

	/**
	 * returns true if this list contains an element that has the same value as
	 * the specified element
	 */
	public boolean contains(T o) {
		boolean status = false;
		if (size == 0) {
			return false;
		} else {
			NodeD<T> temp = header.getNext();
			while (temp.getNext().getNext() != null && !status) {
				if (temp.getElement().equals(o)) {
					status = true;
				}
				temp = temp.getNext();
			}
			if (temp.getElement().equals(o)) {
				status = true;
			}
		}
		return status;
	}

	/**
	 * returns an iterator to enable the multiple traversals on the list
	 * elements
	 */
	public MyLLIteratorD<T> getIterator() {
		return new MyLLIteratorD<T>(this);
	}
}
